SpringBoot + Maven多模块配置

最近准备跟伙伴合作开发一个OA系统,环境使用SpringBoot + maven,由于在此之前我们都是单兵作战,所以在项目开始前,打算率先解决这个问题。使用SpringBoot + Maven进行多模块配置

开始前,先了解一下maven的几个知识点。

  • groupId:定义当前 Maven 项目隶属的实际项目,一个实际项目下会有多个 Maven 项目。如一家公司开发的产品,groupId 就是公司/个人域名,但会包括众多的 Maven 项目;
  • artifactId:定义实际项目中的一个 Maven 项目,一般用实际项目名称作为 artifactId 的前缀;
  • versioin:指定工程的版本,如 - 1.0 SNAPSHOT,SNAPSHOT 意为快照,说明在该项目还处于开发中;
  • packaging:定义 Maven 项目的打包方式,有 JAR 、WAR 和 EAR 三种格式详情见:JAR,WAR,EAR区别
  • dependencies:所有依赖在此范围添加,包含众多dependency
  • parent:指定当前项目的父模块或者父工程,使用groupId,artifactId定位项目
  • modules:在父模块中引用子模块,所有子模块均包含在里面
  • module:表示一个子模块,使用相对路径

父模块包含子模块(包含)

在用maven管理项目中,可以在当前项目下构建一个子模块。(子模块使用maven构造的话默认继承父模块,若是使用Spring Initializr的话,则需要手动配置父模块)

  • 建立一个父模块

在IDEA中建立一个SpringBoot项目,Group选择公司名字,Artifact选择项目名字。建立好之后,POM.xml大概会是一下的样子。

==值得注意的是==:要将packaging改为pom,因为所有的父模块中的packaging就是pom。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<groupId>com.maven2</groupId>
<artifactId>test2</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>pom</packaging>

<name>test2</name>
<description>Demo project for Spring Boot</description>

<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.2.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>

<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>

<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>


</project>

由于使用SpringBoot,所以最顶层父项目就是spring-boot-starter-parent。逻辑上不影响项目分层。父项目建立了基本依赖。

  • 建立子模块
  1. 右键点击父模块,New -> Module -> Maven
  2. 选择maven-archetype-webapp之后,默认继承父模块的GroupId,需要填写artifactId,此处可填写模块的作用。
  3. 一直点击Next,最后Finish,完成子模块构建

最后生成的pom.xml如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
<?xml version="1.0" encoding="UTF-8"?>

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>test2</artifactId>
<groupId>com.maven2</groupId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>

<artifactId>repository</artifactId>
<packaging>jar</packaging>

<name>repository Maven Webapp</name>
<!-- FIXME change it to the project's website -->
<url>http://www.example.com</url>

<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.7</maven.compiler.source>
<maven.compiler.target>1.7</maven.compiler.target>
</properties>

<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
</dependencies>

<build>
<finalName>repository</finalName>
<pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->
<plugins>
<plugin>
<artifactId>maven-clean-plugin</artifactId>
<version>3.0.0</version>
</plugin>
<!-- see http://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_war_packaging -->
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<version>3.0.2</version>
</plugin>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.7.0</version>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.20.1</version>
</plugin>
<plugin>
<artifactId>maven-war-plugin</artifactId>
<version>3.2.0</version>
</plugin>
<plugin>
<artifactId>maven-install-plugin</artifactId>
<version>2.5.2</version>
</plugin>
<plugin>
<artifactId>maven-deploy-plugin</artifactId>
<version>2.8.2</version>
</plugin>
</plugins>
</pluginManagement>
</build>
</project>

这时父模块中将会添加标签。(可以手动,但大多时候自动)。其中包含了其下的所被继承的子模块,使用指定子模块。

在我的测试项目中建立user,service,repository子模块,他们都继承父模块。又因为父模块继承SpringBoot模块,因此user,service,repository都继承SpringBoot模块,也就是说user,service,repository都是SpringBoot项目

假设A继承B模块,B继承C模块,那么A也将自动继承C模块。

1
2
3
4
5
<modules>
<module>user</module>
<module>service</module>
<module>repository</module>
</modules>
  • 子模块A调用子模块B

概述:子模块A依赖子模块B,所以直接在子模块A上添加子模块B的依赖。

完成user,service,repository三个模块之后,每个模块都是独立的一个项目。此时假设user想要调用service模块中的方法,那将怎么做。

分析:user模块调用service模块可以表示为user模块依赖service模块。因此在此理解基础上,可以为user模块添加一个service模块依赖

1
2
3
4
5
<dependency>
<groupId>com.maven2</groupId>
<artifactId>service</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>

这时就可以引入service中的方法了。

父工程与子工程同级(并列)

父工程与子工程同级的意思是,子工程不在父工程文件夹下,而是与父工程同一级文件夹。

  • 建立父工程

使用Spring Initializr进行构建项目,步骤同上。建立好之后的pom.xml与上面一样。

  • 建立子工程

子工程可以使用maven构建,也可以使用Spring Initializr构建,这两种方法无异。但是在pom.xml中都要使用指定其父工程是哪一个(使用GroupId,ArtifactId进行定位)

1
2
3
4
5
6
<!--为子工程指明父工程-->
<parent>
<groupId>com.maven</groupId>
<artifactId>test</artifactId>
<version>0.0.1-SHAPSHOT</version>
</parent>

此时在maven里的逻辑上已经指明他的父工程,若想使用父工程,则添加父工程依赖

1
2
3
4
5
6
<!--在子工程添加父工程的依赖-->
<dependency>
<groupId>com.maven</groupId>
<artifactId>test</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>

目前,测试时建立两个子工程:TestAdmin和TestUser。他们两个都与父工程TestMaven同级,因此在TestMaven中聚合这两个子工程。使用中使用相对路径

1
2
3
4
5
6
<!--在父工程TestMaven-->
<modules>
<module>../TestUser</module>
<module>../TestAdmin</module>
<module>config</module>
</modules>
  • 配置入口类

由于maven中继承是子工程继承自父工程,而父工程聚合子工程,所以子工程可以添加父工程的依赖,而父工程不能添加子工程依赖,就像儿子可以依赖父亲,父亲却很少依赖儿子一样。

假设入口类在子工程A

子工程A默认引用了父工程的依赖,而没有引用子工程B的依赖,因此当启动叻在子工程A中的启动类时,Spring将扫描子工程A和父工程,而不会扫描子工程B,原因就是没有在子工程A中引入子工程B的依赖。

子工程A没理由也没必要引用子工程B,就像A独立开发A模块,B独立开发B模块,最后必须得将A模块依赖B模块,这样功劳岂不都是B的了,因此这样做在逻辑上说不通。

假设入口类在子工程B

同上

假设入口类在父工程

当入口类在父工程时,在逻辑上说的过去了,因为子工程A,子工程B本来就是从父工程中分离出来的,最后终究要回到父工程,因此由父工程作为启动类位置较为合适。

但是!!!!!假若入口类直接放在父工程中的src - main - java - com - maven - test的包里,由于父工程不能引用子工程AB,因此启动时,将不会扫描子工程AB,貌似情况比之前还要糟糕了。

仔细想想,入口类放在父工程下是没错的,但是就是不能直接放在父工程的代码里,那如果是放在父工程的子模块呢?

试一下,在父工程下建立子模块在前面已经提到过,建立的子模块就是SpringBoot项目。因此将入口类放在子模块中,而在子模块中的pom.xml去引入TestAdmin, TestUser的依赖,好像这样子就可以运行起来了,因为子模块的pom.xml继承自父工程,因此可以直接添加依赖。

当项目运行起来时,可以看到,在父工程下建立子模块,将这个子模块作为整个项目的入口启动类,这样是可以行得通的。

-------------本文结束感谢您的阅读-------------